<?php

namespace Xin\Menu;

use Xin\Capsule\Manager;
use Xin\Menu\Contracts\Factory;
use Xin\Menu\Contracts\Generator;
use Xin\Menu\Generators\DefaultGenerator;
use Xin\Support\Arr;

/**
 * @mixin \Xin\Menu\Contracts\Repository
 */
class MenuManager extends Manager implements Factory
{
    /**
     * 驱动的列表键名
     */
    public const DRIVER_CONFIG_KEY = 'menus';

    /**
     * 默认的驱动键名
     */
    public const DEFAULT_DRIVER_KEY = 'menu';

    /**
     * @var array
     */
    protected $menus = [];

    /**
     * @var array
     */
    protected $customGenerator = [];

    /**
     * @param array $config
     */
    public function __construct(array $config = [])
    {
        parent::__construct($config);

        $this->customGenerator['default'] = function () {
            return new DefaultGenerator();
        };
    }

    /**
     * @inerhitDoc
     */
    public function menu($name = null)
    {
        $name = $name ?: $this->getDefaultDriver();
        return $this->menus[$name] ?? $this->menus[$name] = $this->createMenu($name);
    }

    /**
     * @inerhitDoc
     */
    public function repository($name = null)
    {
        $name = $name ?: $this->getDefaultDriver();
        return $this->driver($name);
    }

    /**
     * 创建菜单器
     * @param string $name
     * @return Menu
     */
    protected function createMenu($name)
    {
        /** @var array $config */
        $config = $this->getMenuConfig($name, null, []);
        $repository = $this->isMakeRepository() ? $this->driver($name) : null;
        $generator = $this->resolveGenerator($name);

        return new Menu($config, $repository, $generator);
    }


    /**
     * 调用生成器
     *
     * @param string|null $name
     * @return Generator
     */
    protected function resolveGenerator(string $name = null)
    {
        $name = $name ?: $this->getDefaultDriver();
        $generatorType = $this->getMenuConfig($name, 'generator', 'default');

        if (!isset($this->customGenerator[$generatorType])) {
            throw new \RuntimeException("Menu Generator[{$generatorType}] not defined.");
        }

        $generator = $this->customGenerator[$generatorType];
        if (is_callable($generator)) {
            $this->customGenerator[$name] = $generator();
        } elseif (is_string($generator)) {
            $this->customGenerator[$name] = app($generator);
        } elseif (is_object($generator)) {
            $this->customGenerator[$name] = $generator;
        } else {
            throw new \RuntimeException("Menu Generator[{$generatorType}] invalid.");
        }

        return $this->customGenerator[$name];
    }


    /**
     * @inerhitDoc
     */
    public function shouldUse($name)
    {
        $name = $name ?: $this->getDefaultDriver();

        $this->setDefaultDriver($name);
    }

    /**
     * 获取菜单配置
     *
     * @param string $menu
     * @param null $name
     * @param null $default
     * @return mixed
     */
    public function getMenuConfig($menu, $name = null, $default = null)
    {
        if ($config = $this->getDriverConfig($menu)) {
            return Arr::get($config, $name, $default);
        }

        throw new \InvalidArgumentException("Menu [$menu] not found.");
    }

    /**
     * @return bool
     */
    protected function isMakeRepository()
    {
        return class_exists(\think\facade\Db::class) || class_exists(\Illuminate\Support\Facades\DB::class);
    }
}
